<?php

namespace app\services;

use app\api\validation\Address;
use app\level\LevelFactory;
use app\payment\PayFactory;
use app\traits\Page;
use plugin\admin\app\model\Exchange;
use plugin\admin\app\model\ExchangeApply;
use plugin\admin\app\model\OrderShippingNotice;
use plugin\admin\app\model\TransferJob;
use plugin\admin\app\model\UserCompanyProduct;
use plugin\admin\app\model\UserLevel;
use plugin\admin\app\model\UserPrizeDraw;
use plugin\admin\app\model\UserProfile;
use plugin\admin\app\model\UserSearchHistory;
use plugin\admin\app\model\UserTeam;
use plugin\admin\app\model\VideoComment;
use plugin\admin\app\model\Goods;
use plugin\admin\app\model\GoodsComment;
use plugin\admin\app\model\GoodsSKU;
use plugin\admin\app\model\Order;
use plugin\admin\app\model\OrderGoods;
use plugin\admin\app\model\OrderRefund;
use plugin\admin\app\model\OrderRefundLog;
use plugin\admin\app\model\OrderReservation;
use plugin\admin\app\model\Reservation;
use plugin\admin\app\model\ShoppingCart;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserActivity;
use plugin\admin\app\model\UserCoupon;
use plugin\admin\app\model\UserProperty;
use plugin\admin\app\model\UserPropertyLog;
use plugin\admin\app\model\UserUpline;
use SimpleSoftwareIO\QrCode\Generator;
use support\Express;
use support\Redis;
use Webman\Config;
use Webman\Event\Event;

class OrderService
{
    public static function count()
    {
        $waiting_pay_count = Order::where('status', Order::STATUS_WAITING_PAY)->whereNull('cancel_time')->where('user_id', get_user_id())->count();
        $waiting_shipping_count = Order::where('status', Order::STATUS_WAITING_SHIPPING)->whereNotNull('pay_time')->whereNull('cancel_time')->where('user_id', get_user_id())->count();
        $waiting_receive_count = Order::where('status', Order::STATUS_WAITING_RECEIVE)->whereNotNull('pay_time')->whereNull('cancel_time')->where('user_id', get_user_id())->count();

        return [
            'waiting_pay_count' => $waiting_pay_count,
            'waiting_shipping_count' => $waiting_shipping_count,
            'waiting_receive_count' => $waiting_receive_count
        ];
    }

    public static function changePayWay($orderNo, $payWay)
    {
        $order = Order::where('order_no', $orderNo)->where('user_id', get_user_id())->first();

        if (!empty($order)) {
            $order->pay_way = $payWay;

            if ($order->pay_way == PayFactory::WECHAT) {
                $order->pay_way_type = 'mini';
            }

            $order->save();
        }
    }

    public static function preview($data)
    {
        if (!empty($data['address_id'])) {
            $addressInfo = AddressService::detail($data['address_id']);
        } else {
            $addressInfo = AddressService::getDefault();
        }

        // 非购物车下单,添加到购物车
        if (empty($data['cart_item_ids'])) {
            $data['cart_item_ids'] = [];

            if (empty($data['goods_id'])) {
                throw new \Exception('商品ID不能为空');
            }

            $data['cart_item_ids'][] = ShoppingCartService::add([
                'sku_id' => $data['sku_id'] ?? 0,
                'goods_id' => $data['goods_id'] ?? 0,
                'count' => $data['count'] ?? 1
            ], 1);
        }

        if (!is_array($data['cart_item_ids'])) {
            $data['cart_item_ids'] = [$data['cart_item_ids']];
        }

//        if (empty($data['coupon_id'])) {
//            $coupons = UserCouponService::getOrderCouponList($data['cart_item_ids']);
//
//            foreach ($coupons as $coupon) {
//                if ($coupon['can_use']) {
//                    $data['coupon_id'] = $coupon['id'];
//                    break;
//                }
//            }
//        }

        $inviteUserInfo = [];
        $userInfo = User::select(['id', 'level', 'parent_id'])->where('id', get_user_id())->first();
        if (!empty($userInfo['parent_id'])) {
            $inviteUserInfo = UserProfile::select(['user_id', 'nickname', 'avatar'])->where('user_id', $userInfo['parent_id'])->first()->toArray();
        }

        $isGiftOrder = ShoppingCartService::isGift($data['cart_item_ids']);

        $list = ShoppingCartService::list($data['cart_item_ids']);
        //活动优惠价格
        $activityPreferentialPrice = $list['totalPreferentialPrice'];
        //总商品价格
        $goodsTotalPrice = $list['totalPrice'];
        //邮费
        $shippingFee = $list['totalShippingFee'];
        //积分使用上限
        $canUseIntegral = $list['totalCanUseIntegral'];

        $couponPreferentialPrice = 0;
        if (!empty($data['coupon_id'])) {
            $coupons = UserCouponService::getOrderCouponList($data['cart_item_ids']);

            foreach ($coupons as $coupon) {
                if ($coupon['id'] == $data['coupon_id'] && $coupon['can_use']) {
                    $couponPreferentialPrice = $coupon['preferential_price'];
                    break;
                }
            }
        }

        //可用积分
        $integralToBalance = ConfigService::get('integral_to_balance');
        $integral = UserPropertyService::getOrderCanUseIntegral($data['cart_item_ids']);

        $integralPrice = 0;
        if (!empty($data['integral'])) {
            if ($canUseIntegral > 0 && $data['integral'] > $canUseIntegral) {
                throw new \Exception('该订单最多只能使用' . $canUseIntegral . '积分');
            }

            if ($data['integral'] > $integral) {
                throw new \Exception('可用积分不足');
            }

            $integralPrice = bcdiv($data['integral'], $integralToBalance, 2);
        }

        //应付金额
        $payPrice = bcadd($goodsTotalPrice, $shippingFee, 2);
        $payPrice = bcsub($payPrice, $couponPreferentialPrice, 2);

        if ($payPrice < $integralPrice) {
            throw new \Exception('积分抵扣额度不能大于总订单金额');
        }

        $payPrice = bcsub($payPrice, $integralPrice, 2);

        return [
            'is_gift_order' => $isGiftOrder,
            'invite_user_info' => $inviteUserInfo,
            'coupon_id' => !empty($data['coupon_id']) ? $data['coupon_id'] : null,
            'goods_list' => $list['list']['valid'],
            'goods_total_market_price' => $list['totalMarketPrice'],
            'goods_total_price' => $goodsTotalPrice,
            'shipping_fee' => $shippingFee,     //运费
            'pay_price' => $payPrice,           //应付金额
            'integral_price' => $integralPrice,                             //积分抵扣
            'address_info' => $addressInfo,
            'activity_preferential_price' => $activityPreferentialPrice,    //活动优惠
            'coupon_preferential_price' => $couponPreferentialPrice,        //优惠券优惠
            'cart_item_ids' => $data['cart_item_ids'],
            'can_use_integral' => UserPropertyService::getOrderCanUseIntegral($data['cart_item_ids']),
            'can_reduce_integral' => UserPropertyService::getOrderCanReduceIntegral($data['cart_item_ids'])
        ];
    }

    public static function create($data)
    {
        $orderPreviewInfo = self::preview($data);

        if ($orderPreviewInfo['is_gift_order']) {
            Event::dispatch('gift-order.before-create', $orderPreviewInfo);
        }

        if (empty($data['address_id'])) {
            throw new \Exception('请选择地址');
        }
        $addressInfo = AddressService::detail($data['address_id']);

        if (empty($data['pay_way'])) {
            throw new \Exception('请选择支付方式');
        }

        $payWayTypes = PayFactory::create($data['pay_way'])->getSupportPayWayTypes();

        if ($payWayTypes && empty($data['pay_way_type'])) {
            throw new \Exception('支付方式类型不能为空');
        }

        if ($payWayTypes && !in_array($data['pay_way_type'], $payWayTypes)) {
            throw new \Exception('不支持支付方式类型');
        }

        $type = Order::TYPE_GOODS;
        if (empty($data['type'])) {
            if ($orderPreviewInfo['is_gift_order']) {
                $type = Order::TYPE_GIFT;
            }
        }


        $orderNo = self::generateOrderNo();

        $orderInsertData = [
            'invite_user_id' => $orderPreviewInfo['invite_user_info']['user_id'] ?? 0,
            'user_id' => get_user_id(),
            'order_no' => $orderNo,
            'price' => $orderPreviewInfo['pay_price'],
            'integral' => $orderPreviewInfo['integral_price'],
            'goods_price' => $orderPreviewInfo['goods_total_price'],
            'activity_preferential_price' => $orderPreviewInfo['activity_preferential_price'],
            'coupon_preferential_price' => $orderPreviewInfo['coupon_preferential_price'],
            'shipping_fee' => $orderPreviewInfo['shipping_fee'],
            'pay_way' => $data['pay_way'],
            'pay_way_type' => $data['pay_way_type'] ?? null,
            'receive_contact' => $addressInfo['contact_name'],
            'receive_mobile' => $addressInfo['contact_mobile'],
            'receive_address' => $addressInfo['province'] . $addressInfo['city'] . $addressInfo['district'] . $addressInfo['address'],
            'remark' => $data['remark'] ?? '',
            'status' => Order::STATUS_WAITING_PAY,
            'created_time' => date('Y-m-d H:i:s'),
            'type' => $type,
            'coupon_id' => $orderPreviewInfo['coupon_id'],
        ];

        if (!empty($orderPreviewInfo['coupon_id'])) {
            UserCouponService::check($orderPreviewInfo['coupon_id']);
        }

        Order::insert($orderInsertData);

        $orderGoodsList = [];

        foreach ($orderPreviewInfo['goods_list'] as $goods) {
            $orderGoodsList[] = [
                'user_id' => get_user_id(),
                'goods_id' => $goods['goods_info']['id'],
                'brand_id' => $goods['goods_info']['brand_id'] ?? 0,
                'sku_id' => $goods['goods_info']['sku']['id'] ?? 0,
                'order_no' => $orderNo,
                'goods_name' => $goods['goods_info']['name'],
                'goods_thumb' => $goods['goods_info']['thumb'],
                'sku' => !empty($goods['goods_info']['sku']) ? json_encode($goods['goods_info']['sku'], JSON_UNESCAPED_UNICODE) : null,
                'count' => $goods['count'],
                'price' => !empty($goods['goods_info']['sku']) ? $goods['goods_info']['sku']['price'] : $goods['goods_info']['price'],
                'activity_info' => json_encode($goods['goods_info']['activity'], JSON_UNESCAPED_UNICODE)
            ];
        }

        OrderGoods::insert($orderGoodsList);

        ShoppingCartService::delete(['ids' => $orderPreviewInfo['cart_item_ids']]);

        return $orderNo;
    }

    public static function cancel($orderNo, $reason = '')
    {
        $order = Order::where('user_id', get_user_id())->where('order_no', $orderNo)->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        switch ($order['type']) {
            default:
                if ($order['status'] != Order::STATUS_WAITING_PAY && $order['status'] != Order::STATUS_WAITING_SHIPPING && $order['status'] != Order::STATUS_WAITING_GET) {
                    throw new \Exception('该订单无法取消');
                }
        }

        if (!empty($reason)) {
            $order->cancel_reason = $reason;
        }

        $order->status = Order::STATUS_CANCEL;
        $order->cancel_time = date('Y-m-d H:i:s');
        $order->save();

        if (!empty($order['coupon_id'])) {
            UserCouponService::back($order['coupon_id']);
        }

        if ($order['pay_time'] && $order['price'] > 0) {
            self::payBack($order);
        }

    }

    public static function delete($orderNo)
    {
        $order = Order::where('user_id', get_user_id())->where('order_no', $orderNo)->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        if ($order->delete_time) {
            throw new \Exception('不存在的订单');
        }

        $order->delete_time = date('Y-m-d H:i:s');
        $order->save();
    }

    public static function getRangeTimeGiftOrderCount($startTime, $endTime, $userId = null)
    {
        $userId = $userId ?? get_user_id();
        return Order::where('type', Order::TYPE_GIFT)->whereBetween('pay_time', [$startTime, $endTime])->whereNull('cancel_time')->whereNotNull('pay_time')->where('user_id', $userId)->count();
    }

    public static function getRangeTimeChildrenGiftOrderCount($startTime, $endTime, $userId = null)
    {
        $users = User::where('parent_id', $userId)->get()->toArray();
        $userIds = array_column($users, 'id');

        return Order::where('type', Order::TYPE_GIFT)->whereBetween('pay_time', [$startTime, $endTime])->whereNull('cancel_time')->whereNotNull('pay_time')->whereIn('user_id', $userIds)->count();
    }

    public static function getOrdersWithDetails($page = 1, $perPage = 10)
    {
        // 查询订单数据
        $query = Order::select(['order_no', 'user_id', 'price', 'created_time', 'pay_way', 'type', 'level', 'level_type', 'product_id'])
            ->whereNotNull('pay_time')
            ->where('user_id', get_user_id())
            ->whereIn('type', [Order::TYPE_UPGRADE_VIP, Order::TYPE_WORK, Order::TYPE_DOWNLOAD]);

        $total = $query->count(); // 获取总条数

        $orders = $query->offset(($page - 1) * $perPage)
            ->limit($perPage)
            ->orderBy('id', 'desc')
            ->get()
            ->toArray();

        // 提取订单号和类型
        $orderNos = array_column($orders, 'order_no');
        $vipOrders = array_filter($orders, fn($order) => $order['type'] == Order::TYPE_UPGRADE_VIP);
        $workOrders = array_filter($orders, fn($order) => $order['type'] == Order::TYPE_WORK);
        $productOrders = array_filter($orders, fn($order) => $order['type'] == Order::TYPE_DOWNLOAD);

        // 查询升级VIP订单的会员等级
        $userLevels = [];
        if (!empty($vipOrders)) {
            $userLevels = UserLevel::select(['id', 'name', 'icon'])->whereIn('id', array_column($vipOrders, 'level'))->get()->keyBy('id')->toArray();

            foreach ($userLevels as $key=>$level) {
                $userLevels[$key]['icon'] = full_url($level['icon']);
            }
        }

        // 查询购买下载权益订单的TransferJob
        $transferJobs = [];
        if (!empty($workOrders)) {
            $transferJobs = TransferJob::select(['id', 'transfer_file_name', 'order_no'])->whereIn('order_no', $orderNos)->get()->keyBy('order_no')->toArray();
        }

        // 查询购买下载权益订单的TransferJob
        $downloadRecords = [];
        if (!empty($productOrders)) {
            $productIds = array_column($productOrders, 'product_id');
            $downloadRecords = UserCompanyProduct::select(['id', 'file_name'])->whereIn('id', $productIds)->get()->keyBy('id')->toArray();
        }

        // 合并数据
        foreach ($orders as &$order) {
            if ($order['type'] == Order::TYPE_UPGRADE_VIP) {
                $vipLevel = $userLevels[$order['level']] ?? null;
                if ($vipLevel) {
                    $vipLevel['name'] .= ($order['level_type'] == 1 ? '开通' : '续费');
                }
                $order['vip_level'] = $vipLevel;
            } elseif ($order['type'] == Order::TYPE_WORK) {
                $order['transfer_job'] = $transferJobs[$order['order_no']] ?? null;
            } elseif ($order['type'] == Order::TYPE_DOWNLOAD) {
                $order['download'] = $downloadRecords[$order['product_id']] ?? null;
            }
            $order['pay_way_text'] = UserPropertyLog::getPayWayText($order['pay_way']);
        }

        // 返回分页数据
        return [
            'total' => $total,
            'page' => $page,
            'length' => $perPage,
            'data' => $orders,
        ];
    }

    public static function list($page, $length, $status, $keyword = '')
    {
        $offset = ($page - 1) * $length;

        $query = Order::select(['order_no', 'status', 'price', 'refund_status', 'pay_way', 'pay_way_type', 'refund_type', 'activity_preferential_price', 'coupon_preferential_price', 'created_time'])->where('user_id', get_user_id())->whereNull('delete_time')->where('type', '<>', Order::TYPE_RECHARGE);

        if ($status > 0) {
            $query = $query->where('status', $status);
        }

        if ($keyword) {
            if (strpos($keyword, 'NO') !== false) {
                $query = $query->where('order_no', $keyword);
            } else {
                $orderGoodsList = OrderGoods::where('user_id', get_user_id())->where('goods_name', 'like', "%{$keyword}%")->get()->toArray();
                $orderNos = array_column($orderGoodsList, 'order_no');
                if (count($orderNos)) {
                    $query = $query->whereIn('order_no', $orderNos);
                }
            }

            KeywordService::add($keyword, UserSearchHistory::TYPE_ORDER);
        }

        $count = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->orderByDesc('id')->get()->toArray();

        $orderNos = array_column($list, 'order_no');
        $orderGoods = OrderGoods::select(['goods_id', 'order_no', 'goods_name', 'goods_thumb', 'count', 'price', 'sku'])->whereIn('order_no', $orderNos)->get()->toArray();

        $comments = GoodsComment::whereIn('order_no', $orderNos)->get()->toArray();
        $mchId = ConfigService::get('mch_id');
        foreach ($list as $key=>$item) {
            $list[$key]['mch_id'] = $mchId;
            $list[$key]['status_text'] = Order::getStatusText($item);
            foreach ($orderGoods as $goods) {
                if ($goods['order_no'] == $item['order_no']) {
                    $sku = !is_null($goods['sku']) ? json_decode($goods['sku'], true) : [];
                    $goods['sku'] = $sku['sku'] ?? [];
                    $goods['sku_id'] = $sku['id'] ?? 0;

                    $goods['is_comment'] = 0;
                    foreach ($comments as $comment) {
                        if ($comment['goods_id'] == $goods['goods_id'] && $goods['order_no'] == $comment['order_no']) {
                            $goods['is_comment'] = 1;
                            break;
                        }
                    }

                    $list[$key]['goods_list'][] = $goods;
                }
            }

            $list[$key]['refund_type_text'] = OrderRefund::getRefundTypeText($item);

            $list[$key]['rest_pay_time'] = self::getRestPayTime($item);
        }

        return Page::wrap($count, $page, $length, $list);
    }

    public static function detail($orderNo)
    {
        $order = Order::select([
            'order_no', 'status', 'price', 'receive_contact', 'receive_mobile', 'receive_address', 'receive_time', 'express_company', 'express_no', 'remark', 'created_time', 'pay_time', 'shipping_time', 'shipping_fee', 'pay_way', 'pay_way_type', 'activity_preferential_price', 'coupon_preferential_price', 'goods_price', 'refund_status', 'refund_type', 'refund_reason'])->where('order_no', $orderNo)->where('user_id', get_user_id())->whereNull('delete_time')->first();

        if (!$order) {
            throw new \Exception('订单不存在');
        }

        $order = $order->toArray();

        $orderGoods = OrderGoods::select(['goods_id', 'order_no', 'goods_name', 'goods_thumb', 'count', 'price', 'activity_info', 'sku'])->where('order_no', $orderNo)->get()->toArray();
        $order['status_text'] = Order::getStatusText($order);

        $comments = GoodsComment::where('order_no', $orderNo)->get()->toArray();
        foreach ($orderGoods as $goods) {
            $goods['activity_info'] = json_decode($goods['activity_info'], true);
            $sku = !is_null($goods['sku']) ? json_decode($goods['sku'], true) : [];
            $goods['sku'] = $sku['sku'] ?? [];
            $goods['sku_id'] = $sku['id'] ?? 0;

            $goods['is_comment'] = 0;
            foreach ($comments as $comment) {
                if ($comment['goods_id'] == $goods['goods_id']) {
                    $goods['is_comment'] = 1;
                    break;
                }
            }

            $order['goods_list'][] = $goods;
        }

        $order['refund_type_text'] = OrderRefund::getRefundTypeText($order);
        $order['pay_way_text'] = UserPropertyLog::getPayWayText($order['pay_way']);
        $order['rest_pay_time'] = self::getRestPayTime($order);
        $order['mch_id'] = ConfigService::get('mch_id');

        return $order;
    }

    public static function getRestPayTime($order)
    {
        $duration = $config['automatic_cancel_order'] ?? 20;
        return strtotime($order['created_time']) + $duration * 60;
    }

    public static function expressList($orderNo, $orderType = 1)
    {
        if ($orderType == 1) {
            $order = Order::select(['express_no', 'user_id'])->where('order_no', $orderNo)->first();
        } else {
            $order = UserPrizeDraw::select(['express_no', 'user_id'])->where('order_no', $orderNo)->first();
        }

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        return self::expressInfo($order);

    }

    public static function expressInfo($order)
    {
        $expressAppCode = ConfigService::get('express_app_code');

        if (empty($expressAppCode)) {
            throw new \Exception('未设置物流服务code, 请在后台->设置->配置中心->商城配置处设置');
        }

        $expressRes = (new Express(getenv('EXPRESS_APPCODE')))->getList($order['express_no']);

        if ($expressRes['status'] == 0) {
            return $expressRes['result'] ?? ['list' => []];
        }

        return ['list' => []];
    }

    public static function refundExpressList($orderNo)
    {
        $order = OrderRefund::where('order_no', $orderNo)->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        if ($order['refund_express_no']) {
            $expressAppCode = ConfigService::get('express_app_code');

            if (empty($expressAppCode)) {
                throw new \Exception('未设置物流服务code, 请在后台->设置->配置中心->商城配置处设置');
            }

            $expressRes = (new Express(getenv('EXPRESS_APPCODE')))->getList($order['refund_express_no']);

            if ($expressRes['status'] == 0) {
                return $expressRes['result'] ?? ['list' => []];
            }
        }

        return ['list' => []];
    }

    public static function payBack($order)
    {
        PayFactory::create($order['pay_way'])->setData(['user_id' => $order['user_id'], 'order_no' => $order['order_no'], 'total_amount' => $order['price'], 'source' => UserPropertyLog::ORDER_PAY_BACK, 'openid' => UserService::getOpenId($order), 'pay_way_type' => $order['pay_way_type']])->payBack();
    }

    public static function pay($orderNo)
    {
        $tryCount = Redis::get('try_count_' . $orderNo) ?? 0;

        if ($tryCount > 1) {
            Redis::del('try_count_' . $orderNo);
            throw new \Exception('支付失败');
        }

        $order = Order::where('order_no', $orderNo)->where('user_id', get_user_id())->first();

        if ($order['status'] > Order::STATUS_WAITING_PAY) {
            throw new \Exception('该订单已支付');
        }

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        if ($order['type'] == Order::TYPE_GIFT ) {
            $limitCount = ConfigService::get('limit_gift_count');

            if (OrderService::getRangeTimeGiftOrderCount(date('Y-m-01 00:00:00'), date('Y-m-t 23:59:59')) + 1 > $limitCount) {
                throw new \Exception('每月仅能下单一次报单产品');
            }
        }

        if ($order['price'] == 0) {
            $payResult = null;
            self::paySuccess($order['order_no']);
        } else {
            $openId = UserService::getOpenId($order);

            try {
                $payResult = PayFactory::create($order['pay_way'])->setData(['order_no' => $orderNo, 'total_amount' => $order['price'], 'source' => UserPropertyLog::PAY_ORDER, 'openid' => $openId, 'pay_way_type' => $order['pay_way_type']])->pay();
            } catch (\Exception $e) {
                //如果是余额支付，余额不足，抵扣部分余额，改用其他支付方式
//                if ($order['pay_way'] == PayFactory::BALANCE) {
//                    $propertyInfo = UserProperty::where('user_id', $order['user_id'])->first();
//                    Redis::incr('try_count_' . $orderNo, 1);
//                    $order['balance'] = $propertyInfo['balance'];
//                    $order['price'] = bcsub($order['price'], $propertyInfo['balance'], 2);
//                    $order['pay_way'] = PayFactory::WECHAT;
//                    $order['pay_way_type'] = 'mini';
//                    $order->save();
//                    [$orderNo, $payResult] = self::pay($order['order_no']);
//                } else {
                    throw $e;
//                }
            }

            if (PaymentService::dontNeedCallback($order['pay_way'])) {
                self::paySuccess($orderNo);
            }
        }

        return [$orderNo, $payResult];
    }


    public static function recharge($amountInfo, $test)
    {
        $userId = get_user_id();

        $orderNo = OrderService::generateOrderNo();

        $order = [
            'user_id' => $userId,
            'type' => Order::TYPE_RECHARGE,
            'price' => $amountInfo['recharge_amount'],
            'status' => Order::STATUS_WAITING_PAY,
            'order_no' => $orderNo,
            'pay_way' => PayFactory::WECHAT,
            'pay_way_type' => 'mini',
            'remark' => $amountInfo['actual_amount'],
            'created_time' => date('Y-m-d H:i:s')
        ];

        $openId = UserService::getOpenId($order);

        Order::insert($order);

        if ($test) {
            $payResult['order_no'] = $orderNo;
        } else {
            $payResult = PayFactory::create($order['pay_way'])->setData(['order_no' => $orderNo, 'total_amount' => $order['price'], 'source' => UserPropertyLog::PAY_ORDER, 'openid' => $openId, 'pay_way_type' => $order['pay_way_type']])->pay();
        }

        return $payResult;
    }

    public static function rechargeSuccess($orderNo)
    {
        $order = Order::where('order_no', $orderNo)->first();

        // 修改订单状态
        $order['pay_time'] = date('Y-m-d H:i:s');
        $order['status'] = Order::STATUS_FINISH;
        $order->save();

        //充值
        PropertyService::add($order['user_id'], PayFactory::BALANCE, $order['remark'], UserPropertyLog::BALANCE_RECHARGE, '', $order['order_no']);

        PropertyService::add($order['user_id'], PayFactory::RECHARGE_BALANCE, $order['remark'], UserPropertyLog::BALANCE_RECHARGE, '', $order['order_no']);

        UserLevelService::levelUpCheck($order['user_id']);

    }

    public static function autoShipping()
    {
        $orders = Order::where('type', Order::TYPE_RECHARGE)->whereNotNull('pay_time')->whereNull('shipping_time')->get();

        foreach ($orders as $order) {

            $res = WechatMiniProgramShippingService::wechatOrderNotShipping($order->toArray());

            if ($res['errcode'] == 0) {
                $order['status'] = Order::STATUS_FINISH;
                $order['shipping_time'] = date('Y-m-d H:i:s');
                $order->save();
            }
        }
    }

    public static function qrcode($orderNo)
    {
        $detail = Order::select([
            'id',
            'check_user_id',
            'check_code',
        ])->where('order_no', $orderNo)->where('user_id', get_user_id())->first();


        if (!$detail) {
            throw new \Exception('不存在的报名活动');
        }

        return (new Generator())->generate($detail['check_code']);
    }

    public static function checkOrderIsPay($orderNo)
    {
        $order = Order::where('order_no', $orderNo)->where('user_id', get_user_id())->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        return !is_null($order['pay_time']);
    }

    public static function confirm($data)
    {
        $order = Order::where('order_no', $data['order_no'])->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        if ($order->user_id != get_user_id() && $order->buyer_user_id != get_user_id()) {
            throw new \Exception('不存在的订单');
        }

        if ($order['status'] != Order::STATUS_WAITING_RECEIVE) {
            throw new \Exception('该订单尚未发货或已收货');
        }

        $order->status = Order::STATUS_FINISH;
        $order->refund_status = 0;
        $order->receive_time = date('Y-m-d H:i:s');
        $order->save();

        UserLevelService::levelUpCheck($order['user_id']);

        Event::dispatch('order.after-confirm', $order);
    }

    public static function checkCode($data)
    {
        $order = Order::where('check_code', $data['check_code'])->where('check_user_id', get_user_id())->first();

        if (!$order) {
            throw new \Exception('不存在的订单');
        }

        if ($order['status'] == Order::STATUS_FINISH) {
            throw new \Exception('该订单已核销');
        }

        $order->status = Order::STATUS_FINISH;
        $order->refund_status = 0;
        $order->receive_time = date('Y-m-d H:i:s');
        $order->save();
    }

    // 普通商品购买成功之后逻辑
    public static function paySuccess($orderNo)
    {
        $order = Order::where('order_no', $orderNo)->first();

        // 修改订单状态
        $order['pay_time'] = date('Y-m-d H:i:s');
        $order['status'] = Order::STATUS_WAITING_SHIPPING;
        $order->save();

        if ($order['type'] == Order::TYPE_GIFT) {
            Event::dispatch('gift-order.after-pay', $order);
        }

        Event::dispatch('order.after-pay', $order);

        if ($order['type'] != Order::TYPE_RECHARGE) {
            (new ModelService())->reduceIntegral($order);

            if ($order['pay_way'] != PayFactory::BALANCE && $order['balance'] > 0) {
                PropertyService::reduce($order['user_id'], PayFactory::BALANCE, $order['balance'], UserPropertyLog::PAY_ORDER, '', $order['order_no']);
            }
        }
    }

    public static function rebate($order)
    {
        $userInfo = User::where('id', $order['user_id'])->first();

        $parentInfo = User::where('id', $userInfo['parent_id'])->first();

        if (!$parentInfo) {
            return;
        }

        if (!UserService::isVip($parentInfo)) {
            return;
        }

        $rebateRate = UserService::getRebateRate($parentInfo);
        $commission = bcmul($order['price'], $rebateRate / 100, 2);

        if ($commission > 0) {
            PropertyService::add($parentInfo['id'], PayFactory::COMMISSION, $commission, UserPropertyLog::REBATE_INTEGRAL_INCOME, '', $order['order_no']);
        }
    }

    public static function generateOrderNo()
    {
        return 'NO' . substr(str_shuffle("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 11) . mt_rand(1000, 9999);
    }

    public static function generateCheckCode()
    {
        return 'C' . substr(str_shuffle("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 6) . mt_rand(1000, 9999);
    }

    public static function refundList($page, $length, $status)
    {
        $offset = ($page - 1) * $length;
        $query = Order::select(['order_no', 'status', 'price', 'refund_status', 'refund_type', 'refund_desc', 'back_time'])->where('user_id', get_user_id())->where('refund_status', '<>', 0)->whereNull('delete_time');

        if ($status) {
            switch ($status) {
                case 1: //处理中
                    $query = $query->whereIn('refund_status', [1]);
                    break;
                case 2: //已完成
                    $query = $query->whereIn('refund_status', [2, -1, 3, -2]);
                    break;

            }
        }

        $count = (clone $query)->count();
        $list = $query->offset($offset)->limit($length)->orderBy('id', 'desc')->get()->toArray();

        $orderNos = array_column($list, 'order_no');
        $orderGoods = OrderGoods::select(['order_no', 'goods_name', 'goods_thumb', 'sku', 'count', 'price'])->whereIn('order_no', $orderNos)->get()->toArray();

        foreach ($list as $key=>$item) {
            $list[$key]['status_text'] = Order::getStatusText($item);
            $list[$key]['refund_type_text'] = OrderRefund::getRefundTypeText($item);
            $list[$key]['refund_status_text'] = OrderRefund::getStatusText($item['refund_status']);
            foreach ($orderGoods as $goods) {
                if ($goods['order_no'] == $item['order_no']) {
                    $sku = !is_null($goods['sku']) ? json_decode($goods['sku'], true) : [];
                    $goods['sku'] = $sku['sku'] ?? [];
                    $list[$key]['goods_list'][] = $goods;
                }
            }
        }

        return Page::wrap($count, $page, $length, $list);
    }

    public static function noticeShipping($orderNo)
    {
        $order = Order::where('order_no', $orderNo)->where('user_id', get_user_id())->first();

        if (!$order) {
            throw new \Exception('订单不存在');
        }

        if ($order['status'] == Order::STATUS_WAITING_RECEIVE) {
            throw new \Exception('该订单已发货');
        }

        if (OrderShippingNotice::where('order_no', $orderNo)->where('status', OrderShippingNotice::UN_PROCESS)->count() > 0) {
            throw new \Exception('你已提醒发货');
        }

        OrderShippingNotice::insert([
            'order_no' => $orderNo,
            'created_time' => date('Y-m-d H:i:s'),
            'status' => OrderShippingNotice::UN_PROCESS
        ]);
    }

    public static function refundDetail($data)
    {
        $order = Order::select(['order_no', 'status', 'price', 'refund_status', 'refund_type', 'receive_contact', 'receive_mobile', 'receive_address', 'receive_time', 'express_no', 'express_company', 'refund_desc', 'back_time', 'pay_way'])->where('user_id', get_user_id())->where('order_no', $data['order_no'])->whereNull('delete_time')->first();

        if (!$order) {
            throw new \Exception('该商品没有退款信息');
        }

        $order = $order->toArray();

        $orderRefund = OrderRefund::where('order_no', $order['order_no'])->orderByDesc('created_time')->first();

        if ($orderRefund) {
            $orderRefund = $orderRefund->toArray();
        } else {
            $orderRefund = [];
        }

        $order['refund_reason'] = $orderRefund['refund_reason'] ?? '';
        $order['refund_express_no'] = $orderRefund['refund_express_no'] ?? '';
        $order['refund_express_company'] = $orderRefund['refund_express_company'] ?? '';
        $order['created_time'] = $orderRefund['created_time'] ?? '';
        $order['reject_time'] = $orderRefund['reject_time'] ?? '';
        $order['agree_time'] = $orderRefund['agree_time'] ?? '';

        $config = ConfigService::getByGroup('receive');

        $order['receive_info'] = $config;

        $orderGoods = OrderGoods::select(['order_no', 'goods_name', 'goods_thumb', 'sku', 'count', 'price'])->where('order_no', $order['order_no'])->get()->toArray();
        $order['status_text'] = Order::getStatusText($order);
        $order['refund_type_text'] = OrderRefund::getRefundTypeText($order);
        $order['refund_status_text'] = OrderRefund::getStatusText($order['refund_status']);
        $order['refund_wallet_text'] = OrderRefund::getRefundWalletText($order);
        foreach ($orderGoods as $goods) {
            $sku = !is_null($goods['sku']) ? json_decode($goods['sku'], true) : [];
            $goods['sku'] = $sku['sku'] ?? [];
            $order['goods_list'][] = $goods;
        }


        return $order;
    }

    public static function refundHistory($data)
    {
        $orderRefunds = OrderRefund::where('order_no', $data['order_no'])->orderByDesc('created_time')->get()->toArray();

        $kefuInfo = [
            'nickname' => '系统客服',
            'avatar' => '',
        ];

        $userInfo = UserProfile::select(['nickname', 'avatar'])->where('user_id', $orderRefunds[0]['user_id'])->first();
        $order = Order::where('order_no', $data['order_no'])->first();

        $infos = [];
        foreach ($orderRefunds as $orderRefund) {
            $orderRefundLogs = OrderRefundLog::where('refund_id', $orderRefund['id'])->orderByDesc('created_time')->get()->toArray();

            foreach ($orderRefundLogs as $orderRefundLog) {
                switch ($orderRefundLog['status']) {
                    case OrderRefund::UNPROCESS:
                        $infos[] = [
                            'user_info' => $userInfo,
                            'time' => $orderRefundLog['created_time'],
                            'status' => $orderRefundLog['status'],
                            'status_text' => OrderRefund::getStatusText($orderRefundLog['status']),
                            'list' => [
                                [
                                    'label' => '退款类型',
                                    'value' => OrderRefundService::getRefundTypeText($orderRefund['refund_type'])
                                ],
                                [
                                    'label' => '退款金额',
                                    'value' => $orderRefund['refund_amount']
                                ],
                                [
                                    'label' => '退款原因',
                                    'value' => $orderRefund['refund_reason']
                                ],
                                [
                                    'label' => '退款说明',
                                    'value' => $orderRefund['refund_desc']
                                ],
                            ]
                        ];
                        break;
                    case OrderRefund::AGREE:
                        $infos[] = [
                            'user_info' => $kefuInfo,
                            'time' => $orderRefundLog['created_time'],
                            'status' => $orderRefundLog['status'],
                            'list' => [
                                [
                                    'label' => '退款金额',
                                    'value' => $orderRefund['refund_amount']
                                ],
                                [
                                    'label' => '退款账户',
                                    'value' => Order::getWallet($order['pay_way']),
                                ]
                            ]
                        ];
                        break;
                    case OrderRefund::REJECT:
                        $infos[] = [
                            'user_info' => $kefuInfo,
                            'time' => $orderRefundLog['created_time'],
                            'status' => $orderRefundLog['status'],
                            'list' => [
                                [
                                    'label' => '拒绝原因',
                                    'value' => $orderRefund['reject_reason']
                                ],
                                [
                                    'label' => '拒绝说明',
                                    'value' => $orderRefund['reject_desc']
                                ]
                            ]
                        ];
                        break;
                    case OrderRefund::CANCEL:
                        $infos[] = [
                            'user_info' => $userInfo,
                            'time' => $orderRefundLog['created_time'],
                            'status' => $orderRefundLog['status'],
                            'list' => [
                                [
                                    'label' => '取消原因',
                                    'value' => $orderRefund['cancel_reason']
                                ],
                            ]
                        ];
                        break;
                }
            }
        }

        return $infos;
    }

    public static function autoCancel()
    {
        $config = ConfigService::getByGroup('shop');

        $duration = $config['automatic_cancel_order'] ?? 20;
        $expiryDatetime = strtotime('-' . $duration . ' minutes');
        $orders = Order::whereNull('pay_time')->whereNull('cancel_time')->where('created_time', '<', date('Y-m-d H:i:s', $expiryDatetime))->get()->toArray();

        $orderIds = array_column($orders, 'id');

        if ($orderIds) {
            Order::whereIn('id', $orderIds)->update(['cancel_time' => date('Y-m-d H:i:s'), 'status' => Order::STATUS_CANCEL]);
        }

    }

    public static function autoReceive()
    {
        $config = ConfigService::getByGroup('shop');

        $duration = $config['automatic_receive_order'] ?? 7;
        $expiryDatetime = strtotime('-' . $duration . ' days');
        $orders = Order::where('status', Order::STATUS_WAITING_RECEIVE)->where('shipping_time', '<', date('Y-m-d H:i:s', $expiryDatetime))->get()->toArray();

        $orderIds = array_column($orders, 'id');

        if ($orderIds) {
            Order::whereIn('id', $orderIds)->update(['receive_time' => date('Y-m-d H:i:s'), 'status' => Order::STATUS_FINISH]);
        }
    }

    public static function totalAmount()
    {
        return Order::whereNotNull('pay_time')->whereNull('cancel_time')->whereNull('delete_time')->sum('price');
    }

    public static function amountSta($startTime, $endTime)
    {
        return Order::whereBetween('pay_time', [$startTime, $endTime])->whereNull('cancel_time')->whereNull('delete_time')->whereNotNull('pay_time')->sum('price');
    }

}